package sf.database.mapper;

import sf.common.wrapper.Page;
import sf.core.DBObject;
import sf.database.dao.DBClient;
import sf.database.dialect.DBDialect;
import sf.database.jdbc.sql.ModelSql;
import sf.database.template.CType;
import sf.dynamicsql.mapper.DynmicSQLMapper;
import sf.dynamicsql.mapper.DynmicSQLMapperImpl;
import sf.jooq.mapper.JooqMapper;
import sf.jooq.mapper.JooqMapperImpl;
import sf.querydsl.mapper.QueryDSLMapper;
import sf.querydsl.mapper.QueryDSLMapperImpl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * daoMapper实现类
 * @param <T>
 */
public class DaoMapperImpl<T extends DBObject> implements DaoMapper<T> {
    protected DBClient dbClient;
    protected Class<T> domainClass;

    protected volatile JooqMapper<T> jooqMapper;
    protected volatile QueryDSLMapper<T> queryDSLMapper;
    protected volatile DynmicSQLMapper<T> dynmicSQLMapper;

    public DaoMapperImpl(Class<T> domainClass, DBClient dbClient) {
        this.domainClass = domainClass;
        this.dbClient = dbClient;
    }

    @Override
    public int merge(T entity) {
        return getDbClient().merge(entity);
    }

    @Override
    public int insert(T t) {
        return getDbClient().insert(t);
    }

    @Override
    public int[] insertBatch(List<T> list) {
        return getDbClient().batchInsert(list);
    }

    @Override
    public int[] insertBatchFast(List<T> list) {
        return getDbClient().batchInsertFast(list);
    }

    @Override
    public int updateById(T entity) {
        return getDbClient().update(entity);
    }

    @Override
    public int update(T entity) {
        return getDbClient().update(entity);
    }

    @Override
    public int[] updateBatch(List<T> entity) {
        return getDbClient().batchUpdate(entity);
    }

    @Override
    public int delete(T entity) {
        return getDbClient().delete(entity);
    }

    @Override
    public int deleteById(Object... key) {
        return getDbClient().deleteByPrimaryKeys(domainClass, key);
    }

    @Override
    public int[] deleteInBatch(Iterable<T> entities) {
        return getDbClient().batchDelete(asList(entities));
    }

    @Override
    public void deleteAllInBatch() {
        getDbClient().truncate(domainClass);
    }

    @Override
    public int logicDelete(T entity) {
        return getDbClient().logicDelete(entity);
    }

    @Override
    public int logicDeleteById(Object... key) {
        return getDbClient().logicDeleteByPrimaryKeys(domainClass, key);
    }
///////////////////////////////分割线，写方法在上，读方法在下///////////////////////////////////

    @Override
    public T unique(Object... keys) {
        return getDbClient().selectByPrimaryKeys(domainClass, keys);
    }

    @Override
    public T single(T query) {
        return getDbClient().selectOne(query);
    }

    @Override
    public T lock(T query) {
        return getDbClient().selectOneForUpdate(query);
    }

    @Override
    public long count() {
        DBDialect dialect = getDbClient().getDialect(false);
        String sql = ModelSql.getSelectCountSql(dialect, domainClass);
        Long count = getDbClient().selectOne(Long.class, sql);
        if (count == null) {
            count = 0L;
        }
        return count;
    }

    @Override
    public long count(T query) {
        return getDbClient().selectCount(query);
    }

    @Override
    public boolean existsById(Object... id) {
        return getDbClient().existsByPrimaryKeys(domainClass, id);
    }

    @Override
    public boolean exists(T query) {
        return getDbClient().exists(query);
    }

    @Override
    public List<T> selectList(T query) {
        return getDbClient().selectList(query);
    }

    @Override
    public Page<T> selectPage(T query, int start, int size) {
        return getDbClient().selectPage(query, start, size);
    }

    //////////////// 模板sql ///////////////
    @Override
    public List<T> selectTemplate(String sql, Map<String, Object> paras) {
        return getDbClient().selectListTemplate(domainClass, sql, CType.source, paras);
    }

    @Override
    public int executeTemplate(String sql, Map<String, Object> paras) {
        return getDbClient().executeTemplate(sql, CType.source, paras);
    }

    //////////////////////////////////
    @Override
    public DynmicSQLMapper<T> getDynmicSQLMapper() {
        if (dynmicSQLMapper == null) {
            dynmicSQLMapper = new DynmicSQLMapperImpl<>(getDbClient(), domainClass);
        }
        return dynmicSQLMapper;
    }

    @Override
    public JooqMapper<T> getJooqMapper() {
        if (jooqMapper == null) {
            jooqMapper = new JooqMapperImpl<>(getDbClient(), domainClass);
        }
        return jooqMapper;
    }

    @Override
    public QueryDSLMapper<T> getQueryDSLMapper() {
        if (queryDSLMapper == null) {
            queryDSLMapper = new QueryDSLMapperImpl<>(getDbClient(), domainClass);
        }
        return queryDSLMapper;
    }

    // //////////////////////// 分割线 ///////////////////////////

    private <S> List<S> asList(Iterable<S> entities) {
        List<S> list = new ArrayList<>();
        for (S entity : entities) {
            list.add(entity);
        }
        return list;
    }

    @Override
    public DBClient getDbClient() {
        return dbClient;
    }

    @Override
    public Class<T> getDomainClass() {
        return domainClass;
    }
}
